﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ZooKeeperNet;

namespace ZooKeeperManage
{
    /// <summary>
    /// 工作服务器信息
    /// </summary>
    public class WorkData
    {
        public string Name { get; set; }
        public string Data { get; set; }
        public string NodeId { get; set; }
    }

    /// <summary>
    /// 服务器
    /// </summary>
    public class WorkServer : IDisposable
    {
        /// <summary>
        /// 记录服务器状态
        /// </summary>
        private bool _state;

        private readonly string _serverPath;
        /// <summary>
        /// Master节点对应zookeeper中的节点路径
        /// </summary>
        private readonly string _masterPath;
        /// <summary>
        ///  记录当前节点的基本信息
        /// </summary>
        private readonly WorkData _serverData;
        /// <summary>
        /// 记录集群中Master节点的基本信息
        /// </summary>
        private WorkData _masterData;
        /// <summary>
        /// 序列化
        /// </summary>
        private readonly ISerialize _serializ;

        private readonly ZooKeeperService _zkService;

        public WorkServer(WorkData rd, string serverPath = "/Server", string masterPath = "master", ISerialize serialize = null)
        {
            _serverData = rd; // 记录服务器基本信息
            _serverPath = serverPath + "/" + _serverData.Name;
            //  ss = serverPath + "/" + masterPath ;
            _masterPath = serverPath + "/" + _serverData.Name + "/" + masterPath;
            _zkService = new ZooKeeperService();
            if (serialize == null) _serializ = new SerializeJson();
            _zkService.NodeDeleted += path =>
            {
                if (_masterData != null && _masterData.NodeId.Equals(_serverData.NodeId))
                    TakeMaster();
                else
                    Task.Run(() =>
                    {
                        //延迟5秒后再抢。主要是应对网络抖动，给上一轮的Master服务器优先抢占master的权利，避免不必要的数据迁移开销
                        Thread.Sleep(5 * 1000);
                        TakeMaster();
                    });
            };
        }
        /// <summary>
        /// 启动服务器
        /// </summary>
        public void Start()
        {
            if (_state) throw new Exception("server has startup...");//服务器已启动

            string nodeId = "";
            //注册服务
            if (_zkService.Create(_serverPath + "/Work", _serializ.Serializer(_serverData), Ids.OPEN_ACL_UNSAFE, CreateMode.EphemeralSequential, ref nodeId) == CreateResultEnum.Success)
            {
                _state = true;
                _serverData.NodeId = nodeId;
                // 争抢Master权利
                TakeMaster();
                // 订阅Master节点删除事件
                _zkService.SubscribeNodeDeleted(_masterPath);

            }
        }

        /// <summary>
        /// 停止服务器
        /// </summary>
        public void Stop()
        {
            if (!_state) throw new Exception("server has Stopped");//服务器已停止

            _state = false;
            _zkService.Delete(_serverPath + "/Work");
            // 取消Master节点事件订阅
            // 释放Master权利
            ReleaseMaster();
        }

        public List<string> GetChildren()
        {
            return _zkService.GetChildren(_serverPath);
        }

        // 争抢Master
        public void TakeMaster()
        {
            if (!_state)
                return;

            try
            {
                _masterData = new WorkData()
                {
                    Name = _serverData.Name,
                    NodeId = _serverData.NodeId,
                    Data = _serverData.Data,
                };
                // 尝试创建Master临时节点
                if (_zkService.Create(_masterPath, _serializ.Serializer(_masterData), Ids.OPEN_ACL_UNSAFE, CreateMode.Ephemeral) == CreateResultEnum.Success)
                {

                }
                //获取主机信息
                CheckMaster();

            }
            catch (Exception)
            {
                // ignore;
            }

        }
        /// <summary>
        /// 释放Master权利
        /// </summary>
        public void ReleaseMaster()
        {
            if (CheckMaster()) _zkService.Delete(_masterPath);
        }

        /// <summary>
        /// 检测自己是否为Master
        /// </summary>
        /// <returns></returns>
        private bool CheckMaster()
        {
            try
            {
                _masterData = _serializ.Deserialize<WorkData>(_zkService.GetData(_masterPath));
                _serializ.Deserialize<WorkData>(new byte[] { });
                //获取主机信息
                if (_masterData.NodeId.Equals(_serverData.NodeId)) return true;

                return false;
            }
            catch (Exception)
            {
                return false; // 节点不存在，自己肯定不是Master了
            }
        }

        public void Dispose()
        {

            _zkService.Dispose();
        }
    }


}
